package roborally.util;

import java.util.Random;
import java.util.Set;

import be.kuleuven.cs.som.annotate.*;
import roborally.Board;
import roborally.Pieces.*;
/**
 * This is an enum representing basic commands for a Program.
 * 
 * @version 3.0
 * @author 	Bart Opsomer 2de Bachelor Ingenieurswetenschappen Electrotechniek-Computerwetenschappen 
 * 		   	Peter Opsomer 1ste Master Wiskundige IngenieursTechnieken
 */
public enum CommandWordsBasicCommand {
	// all possible enums of this class, with the implemented methods
	MOVE("move", new  Class[]{Robot.class}){
		@Override
		public void execute(Object[] arguments) {
			if(this.args[0] == arguments[0].getClass()) {
				Robot robot = (Robot) arguments[0];
				// Board.move has precondition for Energy
				if(!robot.getEnergy().isGreaterThanOrEquals(robot.getMoveEnergy() )){
					return;
				}
				robot.getPosition().getBoard().moveRobot(robot);
			}
		}
	}
	,
	TURN("turn", new  Class[]{Robot.class,String.class}) {
		@Override
		public void execute(Object[] arguments) {
			if(this.args[0] == arguments[0].getClass() && this.args[1] == arguments[1].getClass() ) {
				Robot robot = (Robot) arguments[0];
				// Robot.turn... has precondition for Energy
				if(!robot.getEnergy().isGreaterThanOrEquals(robot.getTurnEnergy() )){
					return;
				}
				String direction = (String) arguments[1];
				if("clockwise".equals(direction)) {
					robot.turnClockwise();
				}
				if("counter-clockwise".equals(direction)) {
					robot.turnCounterClockwise();
				}
			}
			
		}
	},SHOOT("shoot", new  Class[]{Robot.class}) {
		@Override
		public void execute(Object[] arguments) {
			if(this.args[0] == arguments[0].getClass()) {
				Robot robot = (Robot) arguments[0];
				// Board.shoot has no precondition for Energy but check
				if(!robot.getEnergy().isGreaterThanOrEquals(robot.getShootEnergy() )){
					return;
				}
				robot.getPosition().getBoard().shoot(robot);
			}
			
		}
	},PICKUPANDUSE("pickup-and-use", new  Class[]{Robot.class}) {
		@Override
		public void execute(Object[] arguments) {
			if(this.args[0] == arguments[0].getClass()) {
				Robot robot = (Robot) arguments[0];
				Position position = robot.getPosition();
				Board board = position.getBoard();
				Set<Item> itemsAt = board.getItemsAt(position);
				Item[] items = (Item[]) itemsAt.toArray(new Item[itemsAt.size()]);
				Random random = new Random();
				Item itemToPickUp = items[random.nextInt(items.length)];
				robot.pickupItem(itemToPickUp);
				robot.use(itemToPickUp);
			}
		}
	};
	// the textual representation of this basicCommand
	String text;
	// The array of classes in the order, that is necessary for its exectute method
	Class<?>[] args;
	/**
	 * the constructor of the enums
	 * @param word the textual representation of the enum 
	 * @param args the list of arguments necessary of for the exectute method
	 */
	@Raw
	CommandWordsBasicCommand(String word,Class<?>[] args){
		this.text = word;
		this.args = args;
	}
	/**
	 * @return the text of this CommandWordsBasicCommand
	 */
	@Basic
	public String getText() {
		return this.text;
	}
	/**
	 * @return the class of the arguments for the execute method
	 */
	@Basic
	public Class<?>[] getArgs() {
		return args;
	}
	/**
	 * Get the CommandWordsBasicCommand that the given String represents.
	 * 
	 * @param command the String representing an CommandWordsBasicCommand
	 * @return | result == null || result.getText().equals(command)
	 */
	public static CommandWordsBasicCommand fromString(String command) {
		if (command != null) {
			for (CommandWordsBasicCommand c : CommandWordsBasicCommand.values()) {
				if (command.equals(c.getText())) {
					return c;
				}
			}
		}
		return null;
	}
	/**
	 * the execute method, depending on the enum other effect take place
	 * @param arguments the arguments of this method
	 */
	public abstract void execute(Object[] arguments);
}

